//
// Created by ezio on 20-3-16.
//

#include "cam_module.h"
//sample_vio.c SAMPLE_VIO_ViDeMuxYuv

CAM_MODULE::CAM_MODULE()
{
    is_vi_init =false;
    is_vpss_init =false;
    is_venc_init =false;
    is_vo_init =false;
    this->is_vpssbindvo = false;

    this->cam_nums_=1;
    this->vo_nums_ =1;
    this->vo_mode_ = VO_MODE_1MUX;
    this->enWDRMode      = WDR_MODE_NONE;

}
enum err_code_cam_module
{ ERR_SETUPVI = -999,
    ERR_SETUPVPSS = -1000,
    ERR_SETUPVENC = -1001,
    ERR_SETUPVO = -1002,
    ERR_VPSSBINDVO = -1003,
    ERR_VONUMS = -1004,
    ERR_START = -1005

};
int CAM_MODULE::Init() {

}

int CAM_MODULE::SetupWDR()
{
    this->enWDRMode      = WDR_MODE_2To1_LINE;
    //?如果是WDR= 2to1 是不是最多支持3个相机？
    //WDR= 3to1 是不是最多支持2个相机？

}

//use vi bind vpss , vpss bind vo
HI_S32 CAM_MODULE::start()
{

    HI_S32             s32Ret=0;

    VI_DEV             ViDev[VI_MAX_DEV_NUM]       = {0, 1, 2, 3};
    VI_PIPE            ViPipe[VI_MAX_DEV_NUM]      = {0, 1, 2, 3};//{2,3,4,5};//
    VI_CHN             ViChn          = 0;
    HI_S32             s32WorkSnsId   = 0;
    SAMPLE_VI_CONFIG_S stViConfig;

    SIZE_S             stSize;
    VB_CONFIG_S        stVbConf;
    PIC_SIZE_E         enPicSize;
    HI_U32             u32BlkSize;

    VO_CHN             VoChn[4]          = {0, 1, 2, 3};
    SAMPLE_VO_CONFIG_S stVoConfig;


    DYNAMIC_RANGE_E    enDynamicRange = DYNAMIC_RANGE_SDR8;
    PIXEL_FORMAT_E     enPixFormat    = PIXEL_FORMAT_YVU_SEMIPLANAR_420;
    VIDEO_FORMAT_E     enVideoFormat  = VIDEO_FORMAT_LINEAR;
    COMPRESS_MODE_E    enCompressMode = COMPRESS_MODE_NONE;

    VPSS_GRP           VpssGrp[4]        = {0, 1 ,2, 3};
    VPSS_GRP_ATTR_S    stVpssGrpAttr;
    VPSS_CHN           VpssChn        = VPSS_CHN0;
    HI_BOOL            abChnEnable[VPSS_MAX_PHY_CHN_NUM] = {HI_FALSE};
    VPSS_CHN_ATTR_S    astVpssChnAttr[VPSS_MAX_PHY_CHN_NUM];
#ifdef WITHVENC
    VENC_CHN           VencChn[1]  = {0};
    PAYLOAD_TYPE_E     enType      = PT_H265;
    SAMPLE_RC_E        enRcMode    = SAMPLE_RC_CBR;
    HI_U32             u32Profile  = 0;
    VENC_GOP_ATTR_S    stGopAttr;
#endif



    /*config vi*/
    SAMPLE_COMM_VI_GetSensorInfo(&stViConfig);

    stViConfig.s32WorkingViNum                                   = this->cam_nums_;//s32ViCnt;

    for(int i=0; i<this->cam_nums_; i++) {

        stViConfig.as32WorkingViId[i] = i;
        stViConfig.astViInfo[i].stSnsInfo.MipiDev = ViDev[i];
        stViConfig.astViInfo[i].stDevInfo.ViDev = ViDev[i];
        stViConfig.astViInfo[i].stDevInfo.enWDRMode = enWDRMode;
        stViConfig.astViInfo[i].stPipeInfo.enMastPipeMode = VI_OFFLINE_VPSS_OFFLINE;
        switch(enWDRMode)
        {
            case WDR_MODE_NONE:
            {
                stViConfig.astViInfo[i].stPipeInfo.aPipe[0] = ViPipe[i];
                stViConfig.astViInfo[i].stPipeInfo.aPipe[1] = -1;
                stViConfig.astViInfo[i].stPipeInfo.aPipe[2] = -1;
                stViConfig.astViInfo[i].stPipeInfo.aPipe[3] = -1;
            }
                break;
            case WDR_MODE_2To1_LINE:
            {
                stViConfig.astViInfo[i].stPipeInfo.aPipe[0] = ViPipe[0+2*i];
                stViConfig.astViInfo[i].stPipeInfo.aPipe[1] = ViPipe[1+2*i];
                stViConfig.astViInfo[i].stPipeInfo.aPipe[2] = -1;
                stViConfig.astViInfo[i].stPipeInfo.aPipe[3] = -1;
            }
                break;
            default: {
                printf("enWDRMode is not supported \n");
                return ERR_START;
            }
                break;
        }

        stViConfig.astViInfo[i].stChnInfo.ViChn = ViChn;
        stViConfig.astViInfo[i].stChnInfo.enPixFormat = enPixFormat;
        stViConfig.astViInfo[i].stChnInfo.enDynamicRange = enDynamicRange;
        stViConfig.astViInfo[i].stChnInfo.enVideoFormat = enVideoFormat;
        stViConfig.astViInfo[i].stChnInfo.enCompressMode = enCompressMode;


    }
    //what is this for , any documentation?
    stViConfig.astViInfo[0].stPipeInfo.bMultiPipe     = HI_TRUE;
    stViConfig.astViInfo[0].stPipeInfo.bVcNumCfged     = HI_TRUE;
    stViConfig.astViInfo[0].stPipeInfo.u32VCNum[0] = 0;
    stViConfig.astViInfo[0].stPipeInfo.u32VCNum[1] = 1;
    stViConfig.astViInfo[0].stPipeInfo.u32VCNum[2] = 2;
    stViConfig.astViInfo[0].stPipeInfo.u32VCNum[3] = 3;


    /*get picture size*/
    s32Ret = SAMPLE_COMM_VI_GetSizeBySensor(stViConfig.astViInfo[s32WorkSnsId].stSnsInfo.enSnsType, &enPicSize);
    if (HI_SUCCESS != s32Ret)
    {
        SAMPLE_PRT("get picture size by sensor failed!\n");
        return s32Ret;
    }

    s32Ret = SAMPLE_COMM_SYS_GetPicSize(enPicSize, &stSize);
    if (HI_SUCCESS != s32Ret)
    {
        SAMPLE_PRT("get picture size failed!\n");
        return s32Ret;
    }

    /*config vb*/
    hi_memset(&stVbConf, sizeof(VB_CONFIG_S), 0, sizeof(VB_CONFIG_S));
    stVbConf.u32MaxPoolCnt              = 2;

    u32BlkSize = COMMON_GetPicBufferSize(stSize.u32Width, stSize.u32Height, SAMPLE_PIXEL_FORMAT, DATA_BITWIDTH_8, COMPRESS_MODE_SEG, DEFAULT_ALIGN);
    stVbConf.astCommPool[0].u64BlkSize  = u32BlkSize;
    //?
    stVbConf.astCommPool[0].u32BlkCnt   = 20; //10;
    printf("%s, %d , pic buffer size is %d %d \n",__FUNCTION__, __LINE__, stSize.u32Width, stSize.u32Height);
    u32BlkSize = VI_GetRawBufferSize(stSize.u32Width, stSize.u32Height, PIXEL_FORMAT_RGB_BAYER_16BPP, COMPRESS_MODE_NONE, DEFAULT_ALIGN);
    stVbConf.astCommPool[1].u64BlkSize  = u32BlkSize;
    stVbConf.astCommPool[1].u32BlkCnt   = 4;

    s32Ret = SAMPLE_COMM_SYS_Init(&stVbConf);
    if (HI_SUCCESS != s32Ret)
    {
        SAMPLE_PRT("system init failed with %d!\n", s32Ret);
        return s32Ret;
    }

    /*start vi*/
    s32Ret = SAMPLE_COMM_VI_StartVi(&stViConfig);
    if (HI_SUCCESS != s32Ret)
    {
        SAMPLE_PRT("start vi failed.s32Ret:0x%x !\n", s32Ret);
        goto EXIT;
    }

    /*config vpss*/
    hi_memset(&stVpssGrpAttr, sizeof(VPSS_GRP_ATTR_S), 0, sizeof(VPSS_GRP_ATTR_S));
    stVpssGrpAttr.stFrameRate.s32SrcFrameRate    = -1;
    stVpssGrpAttr.stFrameRate.s32DstFrameRate    = -1;
    stVpssGrpAttr.enDynamicRange                 = DYNAMIC_RANGE_SDR8;
    stVpssGrpAttr.enPixelFormat                  = enPixFormat;
    stVpssGrpAttr.u32MaxW                        = stSize.u32Width;
    stVpssGrpAttr.u32MaxH                        = stSize.u32Height;
    stVpssGrpAttr.bNrEn                          = HI_TRUE;
    stVpssGrpAttr.stNrAttr.enCompressMode        = COMPRESS_MODE_FRAME;
    stVpssGrpAttr.stNrAttr.enNrMotionMode        = NR_MOTION_MODE_NORMAL;

    astVpssChnAttr[VpssChn].u32Width                    = stSize.u32Width;
    astVpssChnAttr[VpssChn].u32Height                   = stSize.u32Height;
    astVpssChnAttr[VpssChn].enChnMode                   = VPSS_CHN_MODE_USER;
    astVpssChnAttr[VpssChn].enCompressMode              = enCompressMode;
    astVpssChnAttr[VpssChn].enDynamicRange              = enDynamicRange;
    astVpssChnAttr[VpssChn].enVideoFormat               = enVideoFormat;
    astVpssChnAttr[VpssChn].enPixelFormat               = enPixFormat;
    astVpssChnAttr[VpssChn].stFrameRate.s32SrcFrameRate = 30;
    astVpssChnAttr[VpssChn].stFrameRate.s32DstFrameRate = 30;
    astVpssChnAttr[VpssChn].u32Depth                    = 0;
    astVpssChnAttr[VpssChn].bMirror                     = HI_FALSE;
    astVpssChnAttr[VpssChn].bFlip                       = HI_FALSE;
    astVpssChnAttr[VpssChn].stAspectRatio.enMode        = ASPECT_RATIO_NONE;

    /*start vpss*/
    abChnEnable[0] = HI_TRUE;
    for(int i=0;i<this->cam_nums_;i++) {
        s32Ret = SAMPLE_COMM_VPSS_Start(VpssGrp[i], abChnEnable, &stVpssGrpAttr, astVpssChnAttr);
        if (HI_SUCCESS != s32Ret) {
            SAMPLE_PRT("start vpss group failed. s32Ret: 0x%x !\n", s32Ret);
            goto EXIT1;
        }

        s32Ret = SAMPLE_COMM_VI_Bind_VPSS(ViPipe[i], ViChn, VpssGrp[i]);
        if (HI_SUCCESS != s32Ret)
        {
            SAMPLE_PRT("vi bind vpss failed. s32Ret: 0x%x !\n", s32Ret);
            goto EXIT3;
        }

    }
#ifdef WITH_VENC
    /*config venc */
    stGopAttr.enGopMode  = VENC_GOPMODE_SMARTP;
    stGopAttr.stSmartP.s32BgQpDelta  = 7;
    stGopAttr.stSmartP.s32ViQpDelta  = 2;
    stGopAttr.stSmartP.u32BgInterval = 1200;
    s32Ret = SAMPLE_COMM_VENC_Start(VencChn[0], enType, enPicSize, enRcMode, u32Profile, &stGopAttr);
    if (HI_SUCCESS != s32Ret)
    {
        SAMPLE_PRT("start venc failed. s32Ret: 0x%x !\n", s32Ret);
        goto EXIT2;
    }

    s32Ret = SAMPLE_COMM_VPSS_Bind_VENC(VpssGrp, VpssChn, VencChn[0]);
    if (HI_SUCCESS != s32Ret)
    {
        SAMPLE_PRT("Venc bind Vpss failed. s32Ret: 0x%x !n", s32Ret);
        goto EXIT3;
    }
#endif
    /*config vo*/
    SAMPLE_COMM_VO_GetDefConfig(&stVoConfig);
    stVoConfig.enDstDynamicRange = enDynamicRange;
//    stVoConfig.enVoIntfType = VO_INTF_BT1120;
    stVoConfig.enVoIntfType = VO_INTF_HDMI;

    stVoConfig.enPicSize = enPicSize;

    stVoConfig.enVoMode = this->vo_mode_;

    /*start vo*/
    s32Ret = SAMPLE_COMM_VO_StartVO(&stVoConfig);
    if (HI_SUCCESS != s32Ret)
    {
        SAMPLE_PRT("start vo failed. s32Ret: 0x%x !\n", s32Ret);
        goto EXIT4;
    }

    /*vpss bind vo*/
    for(int i=0;i<this->vo_nums_;i++) {
        s32Ret = SAMPLE_COMM_VPSS_Bind_VO(VpssGrp[i], VpssChn, stVoConfig.VoDev, VoChn[i]);
        if (HI_SUCCESS != s32Ret) {
            SAMPLE_PRT("vo bind vpss failed. s32Ret: 0x%x !\n", s32Ret);
            goto EXIT5;
        }
    }
#ifdef WITH_VENC
    s32Ret = SAMPLE_COMM_VENC_StartGetStream(VencChn, sizeof(VencChn)/sizeof(VENC_CHN));
    if (HI_SUCCESS != s32Ret)
    {
        SAMPLE_PRT("Get venc stream failed!\n");
        goto EXIT6;
    }
#endif

    PAUSE();

#ifdef WITH_VENC
    SAMPLE_COMM_VENC_StopGetStream();
#endif
    EXIT6:
    for(int i=0;i<this->vo_nums_;i++)
        SAMPLE_COMM_VPSS_UnBind_VO(VpssGrp[i], VpssChn, stVoConfig.VoDev, VoChn[i]);
    EXIT5:
    SAMPLE_COMM_VO_StopVO(&stVoConfig);
    EXIT4:
#ifdef WITHVENC
    for(int i=0;i<this->cam_nums_;i++)
        SAMPLE_COMM_VPSS_UnBind_VENC(VpssGrp[i], VpssChn, VencChn[i]);
#endif
    printf("%s %d no operation\n",__FUNCTION__,__LINE__);

    EXIT3:
#ifdef WITHVENC
    SAMPLE_COMM_VENC_Stop(VencChn[0]);
#endif
    printf("%s %d no operation\n",__FUNCTION__,__LINE__);

    EXIT2:
    for(int i=0;i<this->cam_nums_;i++)
        SAMPLE_COMM_VPSS_Stop(VpssGrp[i], abChnEnable);
    EXIT1:
    SAMPLE_COMM_VI_StopVi(&stViConfig);
    EXIT:
    SAMPLE_COMM_SYS_Exit();
    return s32Ret;

}



//最多支持两个相机。
int CAM_MODULE::SetupCamVI(int cam_nums) {
    if(cam_nums<0||cam_nums>2)
        return ERR_SETUPVI;
    this->cam_nums_=cam_nums;
    return 0;

}
#if 0
int CAM_MODULE::SetupVPSS() {

    HI_S32 s32Ret =0;


    VPSS_GRP_ATTR_S    stVpssGrpAttr;
    VPSS_CHN_ATTR_S    astVpssChnAttr[VPSS_MAX_PHY_CHN_NUM];

    /*config vpss*/
    hi_memset(&stVpssGrpAttr, sizeof(VPSS_GRP_ATTR_S), 0, sizeof(VPSS_GRP_ATTR_S));
    stVpssGrpAttr.stFrameRate.s32SrcFrameRate    = -1;
    stVpssGrpAttr.stFrameRate.s32DstFrameRate    = -1;
    stVpssGrpAttr.enDynamicRange                 = DYNAMIC_RANGE_SDR8;
    stVpssGrpAttr.enPixelFormat                  = enPixFormat;
    stVpssGrpAttr.u32MaxW                        = stSize.u32Width;
    stVpssGrpAttr.u32MaxH                        = stSize.u32Height;
    stVpssGrpAttr.bNrEn                          = HI_TRUE;
    stVpssGrpAttr.stNrAttr.enCompressMode        = COMPRESS_MODE_FRAME;
    stVpssGrpAttr.stNrAttr.enNrMotionMode        = NR_MOTION_MODE_NORMAL;

    astVpssChnAttr[VpssChn].u32Width                    = stSize.u32Width;
    astVpssChnAttr[VpssChn].u32Height                   = stSize.u32Height;
    astVpssChnAttr[VpssChn].enChnMode                   = VPSS_CHN_MODE_USER;
    astVpssChnAttr[VpssChn].enCompressMode              = enCompressMode;
    astVpssChnAttr[VpssChn].enDynamicRange              = enDynamicRange;
    astVpssChnAttr[VpssChn].enVideoFormat               = enVideoFormat;
    astVpssChnAttr[VpssChn].enPixelFormat               = enPixFormat;
    astVpssChnAttr[VpssChn].stFrameRate.s32SrcFrameRate = 30;
    astVpssChnAttr[VpssChn].stFrameRate.s32DstFrameRate = 30;
    astVpssChnAttr[VpssChn].u32Depth                    = 0;
    astVpssChnAttr[VpssChn].bMirror                     = HI_FALSE;
    astVpssChnAttr[VpssChn].bFlip                       = HI_FALSE;
    astVpssChnAttr[VpssChn].stAspectRatio.enMode        = ASPECT_RATIO_NONE;

    /*start vpss*/
    abChnEnable[0] = HI_TRUE;
    s32Ret = SAMPLE_COMM_VPSS_Start(VpssGrp, abChnEnable, &stVpssGrpAttr, astVpssChnAttr);
    if (HI_SUCCESS != s32Ret)
    {
        SAMPLE_PRT("start vpss group failed. s32Ret: 0x%x !\n", s32Ret);
        return ERR_SETUPVPSS;
    }
    this->is_vpss_init = true;
}

int CAM_MODULE::SetupVENC() {
    HI_S32 s32Ret =0;



    PAYLOAD_TYPE_E     enType      = PT_H265;
    SAMPLE_RC_E        enRcMode    = SAMPLE_RC_CBR;
    HI_U32             u32Profile  = 0;
    VENC_GOP_ATTR_S    stGopAttr;
    stGopAttr.enGopMode  = VENC_GOPMODE_SMARTP;
    stGopAttr.stSmartP.s32BgQpDelta  = 7;
    stGopAttr.stSmartP.s32ViQpDelta  = 2;
    stGopAttr.stSmartP.u32BgInterval = 1200;
    s32Ret = SAMPLE_COMM_VENC_Start(VencChn[0], enType, enPicSize, enRcMode, u32Profile, &stGopAttr);
    if (HI_SUCCESS != s32Ret)
    {
        SAMPLE_PRT("start venc failed. s32Ret: 0x%x !\n", s32Ret);
        return ERR_SETUPVENC;
    }
    this->is_venc_init =true;
}
#endif

int CAM_MODULE::SetupVO(int vo_nums) {
    if(vo_nums>4||vo_nums<1)
        return ERR_SETUPVO;

    this->vo_nums_ = vo_nums;
    switch(vo_nums_)
    {
        case 1:
            this->vo_mode_ = VO_MODE_1MUX;
            break;
        case 4:
            this->vo_mode_ = VO_MODE_4MUX;
            break;
        default:
            break;
    }

    return 0;

}
int CAM_MODULE::BindVPSStoVO()
{
#if 0
    HI_S32 s32Ret =0;
    s32Ret = SAMPLE_COMM_VPSS_Bind_VO(VpssGrp, VpssChn, stVoConfig.VoDev, VoChn);
    if (HI_SUCCESS != s32Ret)
    {
        SAMPLE_PRT("vo bind vpss failed. s32Ret: 0x%x !\n", s32Ret);
        return ERR_VPSSBINDVO;
    }
    this->is_vpssbindvo = true;
#endif
}


void CAM_MODULE::Stop() {

}

CAM_MODULE::~CAM_MODULE() {
    this->Stop();
}
